using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using mesoBoard.Data.Repositories;
using mesoBoard.Data;
using System.Web.Security;
using mesoBoard.Web;
using System.Text.RegularExpressions;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using mesoBoard.Web.Core;
using System.Configuration;
using mesoBoard.Services;
using System.Net;

namespace mesoBoard.Web.Controllers
{
    [Authorize]
    public partial class UserController : mesoBoardController
    {
        public UserController()
        {
            ViewData["TopBreadCrumb"] = "User CP";
            ViewData["BreadCrumb"] = "User CP";
        }

        public ActionResult UserCP()
        {
            return View();
        }

        [HttpGet]
        public ActionResult ChangeProfile()
        {
            ViewData["BreadCrumb"] = "Modify Profile";
            ViewData["DefaultRole"] = Repositories.Roles.GetRoles(CurrentUser.UserID).Where(x => x.RankID.HasValue);
            ViewData["ThemeID"] = new SelectList(mbServices.Themes.GetVisibleThemes(), "ThemeID", "DisplayName");
            return View(CurrentUser.UserProfile);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult ChangeProfile(UserProfile TheProfile, int? Day, int? Month, int? Year)
        {
            if (Day.HasValue || Month.HasValue || Year.HasValue)
            {
                if (!(Day.HasValue && Month.HasValue && Year.HasValue))
                    ModelState.AddModelError("Birthdate", "Enter the month, day and year of your birthdate");
                else
                {
                    TheProfile.Birthdate = new DateTime(Year.Value, Month.Value, Day.Value);
                }
            }

            if (ModelState.IsValid)
            {
                SetSuccess("Profile updated");
                mbServices.Users.UpdateProfile(TheProfile);
                return RedirectToAction("ChangeProfile");
            }
            else
            {
                SetError("Invalid input");
                ViewData["DefaultRole"] = Repositories.Roles.GetRoles(CurrentUser.UserID).Where(x => x.RankID.HasValue);
                ViewData["ThemeID"] = new SelectList(mbServices.Themes.GetVisibleThemes(), "ThemeID", "DisplayName");
                return View(TheProfile);
            }
        }

        [HttpGet]
        public ActionResult ChangeSignature()
        {
            ViewData["BreadCrumb"] = "Signature";
            return View(CurrentUser.UserProfile);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult ChangeSignature(string Signature)
        {
            ViewData["BreadCrumb"] = "Signature";
            
            CurrentUser.UserProfile.Signature = Signature;

            Repositories.Users.UpdateProfile(CurrentUser.UserProfile);
            SetSuccess("Signature Saved");
            return RedirectToAction("ChangeSignature");
        }

        [HttpPost]
        public ActionResult ChangePassword(string Password, string NewPassword, string ConfirmPassword)
        {
            ViewData["BreadCrumb"] = "Password";
            int MinLength = int.Parse(SiteConfig.PasswordMin.Value);

            if (string.IsNullOrEmpty(Password))
                ModelState.AddModelError("Password", "Enter current password");

            if (!Repositories.Users.ValidateUser(CurrentUser.Username, FormsAuthentication.HashPasswordForStoringInConfigFile(Password + CurrentUser.PasswordSalt, "MD5")))
                ModelState.AddModelError("Password", "Incorrect password");

            if (string.IsNullOrEmpty(NewPassword))
                ModelState.AddModelError("NewPassword", "Enter a new password");

            if (NewPassword.Length < MinLength)
                ModelState.AddModelError("NewPassword", "Minimum password length is " + MinLength + " characters");

            if (NewPassword != ConfirmPassword)
                ModelState.AddModelError("ConfirmPassword", "Confirm password must match");

            if (ModelState.IsValid)
            {
                mbServices.Users.UpdatePassword(CurrentUser.UserID, NewPassword);
                Emailing.PasswordChanged(CurrentUser, NewPassword);
                SetSuccess("Password changed. An email confirmation has been sent");
            }
            else
                SetError("Incorrect password information");

            return View();
        }

        [HttpGet]
        public ActionResult ChangePassword()
        {
            ViewData["BreadCrumb"] = "Password";
            return View();
        }

        [HttpGet]
        public ActionResult ChangeEmail()
        {
            ViewData["BreadCrumb"] = "Email";
            ViewData["CurrentEmail"] = CurrentUser.Email;
            return View();
        }

        [HttpPost]
        public ActionResult ChangeEmail(string NewEmail, string ConfirmEmail)
        {
            ViewData["BreadCrumb"] = "Password";
            ViewData["CurrentEmail"] = CurrentUser.Email;

            if (RegEx.IsValidEmail(NewEmail))
                ModelState.AddModelError("NewEmail", "A valid email address is required");

            if(CurrentUser.Email.ToLower() == NewEmail.ToLower())
                ModelState.AddModelError("NewEmail", "This is the same email as your current email");
            else if (mbServices.Users.EmailInUse(NewEmail))
                ModelState.AddModelError("NewEmail", "This email is already in use by another user");

            if (NewEmail != ConfirmEmail)
                ModelState.AddModelError("ConfirmEmail", "Confirm email must match");

            if (ModelState.IsValid)
            {
                CurrentUser.Email = NewEmail;
                Repositories.Users.UpdateUser(CurrentUser);
                Emailing.EmailChanged(CurrentUser);
                ViewData["CurrentEmail"] = CurrentUser.Email;
                SetSuccess("Email changed. An email confirmation has been sent");
                return RedirectToAction("ChangeEmail");
            }
            else
            {
                ViewData["CurrentEmail"] = CurrentUser.Email;
                SetError("Incorrect email information");
                return View();
            }           
        }
        
        [HttpGet]
        public ActionResult ChangeAvatar()
        {
            ViewData["BreadCrumb"] = "Avatar";
            return View(CurrentUser.UserProfile);
        }

        [HttpPost]
        public ActionResult ChangeAvatar(string AvatarType, string ExternalImageURL)
        {
            
            ViewData["BreadCrumb"] = "Avatar";
            HttpPostedFileBase Avatar = Request.Files["ImageUpload"];
            int MaxHeight =  SiteConfig.AvatarHeight.ToInt();
            int MaxWidth =  SiteConfig.AvatarWidth.ToInt();
            int MaxFileSizeKBsToBytes = SiteConfig.AvatarFileSize.ToInt() * 1024;

            CurrentUser.UserProfile.AvatarType = AvatarType;

            if (AvatarType.Equals("Url"))
            {
                if (string.IsNullOrEmpty(ExternalImageURL))
                    ModelState.AddModelError("ExternalImageURL", "Please enter an image URL");
                else
                {
                    try
                    {
                        WebRequest requestImg = WebRequest.Create(ExternalImageURL);

                        using (WebResponse responseImg = requestImg.GetResponse())
                        {

                            Image img = Image.FromStream(responseImg.GetResponseStream());

                            if (img.Width > MaxWidth || img.Height > MaxHeight)
                                ModelState.AddModelError("ExternalImageURL",
                                    "Image width x height must not exceed " + MaxWidth + " x " + MaxHeight
                                    + " pixels. External image is at " + img.Width + " x " + img.Height);

                        }
                    }
                    catch
                    {
                        ModelState.AddModelError("ExternalImageURL", "An error occurred while retrieving the image, please ensure the URL is correct");
                    }

                }
            }
            else if (AvatarType.Equals("Upload"))
            {
                List<string> validFormats = new List<string> 
                    {
                        "image/png", "image/x-png",
                        "image/gif", "image/x-gif",
                        "image/jpeg", "image/x-jpeg",
                        "image/jpg", "image/x-jpg",
                        
                    };
                if (Avatar == null)
                    ModelState.AddModelError("ImageUpload", "Please select an image to upload");
                else if (!validFormats.Contains(Avatar.ContentType))
                    ModelState.AddModelError("ImageUpload", "Invalid file format; only gif,png,jpeg,jpg are allowed");
                else if (Avatar.ContentLength > MaxFileSizeKBsToBytes)
                    ModelState.AddModelError("ImageUpload", "Image file too large");

            }

            if (ModelState.IsValid)
            {

                switch (AvatarType)
                {
                    case "None":
                        CurrentUser.UserProfile.Avatar = "";
                        break;
                    case "Url":
                        CurrentUser.UserProfile.Avatar = ExternalImageURL;
                        break;
                    case "Upload":
                        string random_name = Randoms.CleanGUID() + Avatar.FileName.Remove(Avatar.FileName.IndexOf('.')) + ".gif";
                        string filePath = Path.Combine(HttpContext.Server.MapPath("~/Upload/Avatars"), random_name);
                        Image ravatar = Image.FromStream(Avatar.InputStream, true, true);
                        if (ravatar.Width > MaxWidth || ravatar.Height > MaxHeight)
                        {
                            ravatar = ravatar.GetThumbnailImage(100, 100, null, IntPtr.Zero);
                        }
                        ravatar.Save(filePath, ImageFormat.Png);

                        CurrentUser.UserProfile.Avatar = random_name;
                        break;
                }

                Repositories.Users.UpdateProfile(CurrentUser.UserProfile);
                SetSuccess("Profile Settings Updated");
                return RedirectToAction("ChangeAvatar");
            }
            else
            {
                SetError("An error occurred");
                return View(CurrentUser.UserProfile);
            }
        }
    }
}
